package coreDb

import (
	"context"
	"errors"
	"fmt"
	"time"

	"gitee.com/xgh2012/api-core/coreBiz"
	"gitee.com/xgh2012/api-core/coreZapLog"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

type PoolSet struct {
	MaxIdleConn int //设置空闲连接池中连接的最大数量
	MaxOpenConn int //设置打开数据库连接的最大数量
	MaxLifeTime int //设置连接可复用的最大时间（分钟）
	MaxIdleTime int //空闲连接存活时间（分钟）
}

type DatabaseCfg struct {
	Username string
	Password string
	Host     string
	Port     string
	Database string
	Charset  string
	LogLevel string
	PoolSet  PoolSet
}

// ConnectDatabase 连接数据库
func ConnectDatabase(cfg *DatabaseCfg) (*gorm.DB, error) {
	var dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true&loc=Local", cfg.Username, cfg.Password, cfg.Host, cfg.Port, cfg.Database, cfg.Charset)
	conn, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true, // 使用单数表名
			TablePrefix:   "",   // 表前缀
		},
		//在打开连接时设置日志级别为Info
		Logger: getLoggerStd(cfg.LogLevel),
	})
	if err != nil {
		return nil, fmt.Errorf("failed to connect to database: %w", err)
	}

	// 配置连接池
	sqlDB, err := conn.DB()
	if err != nil {
		return nil, fmt.Errorf("failed to get underlying sql.DB: %w", err)
	}

	// 设置连接池参数----------------------开始
	// 设置默认值
	maxIdleConn := coreBiz.IfTrueValue(cfg.PoolSet.MaxIdleConn == 0, 15, cfg.PoolSet.MaxIdleConn).(int)
	maxOpenConn := coreBiz.IfTrueValue(cfg.PoolSet.MaxOpenConn == 0, 100, cfg.PoolSet.MaxOpenConn).(int)
	maxLifeTime := coreBiz.IfTrueValue(cfg.PoolSet.MaxLifeTime == 0, 1*time.Hour, time.Duration(cfg.PoolSet.MaxLifeTime)*time.Minute).(time.Duration)
	maxIdleTime := coreBiz.IfTrueValue(cfg.PoolSet.MaxIdleTime == 0, 10*time.Minute, time.Duration(cfg.PoolSet.MaxIdleTime)*time.Minute).(time.Duration)

	sqlDB.SetMaxIdleConns(maxIdleConn)    // 设置空闲连接池中连接的最大数量 保持 30 个空闲连接
	sqlDB.SetMaxOpenConns(maxOpenConn)    // 设置打开数据库连接的最大数量 最大 100 个连接（根据业务调整）
	sqlDB.SetConnMaxLifetime(maxLifeTime) // 设置连接可复用的最大时间 每个连接最长用 1 小时
	sqlDB.SetConnMaxIdleTime(maxIdleTime) // 空闲连接存活时间 空闲 10 分钟就回收

	// 设置连接池参数----------------------结束

	return conn, nil
}

func getLoggerStd(logLevel string) logger.Interface {
	level := logger.Warn
	if logLevel == "debug" || logLevel == "info" {
		level = logger.Info
	} else if logLevel == "error" {
		level = logger.Error
	} else if logLevel == "warn" {
		level = logger.Warn
	} else if logLevel == "none" {
		level = logger.Silent
	}
	return coreZapLog.NewGormLogger(coreZapLog.LoggerSkipGorm, level, 3*time.Second)
}

// IsRealError 真实的错误
func IsRealError(err error) bool {
	if err == nil {
		return false
	}
	return errors.Is(err, gorm.ErrRecordNotFound) == false
}

// IsErrRecordNotFound 未找到记录
func IsErrRecordNotFound(err error) bool {
	return errors.Is(err, gorm.ErrRecordNotFound)
}

// IfTxIsNullGetDB 创建事务
func IfTxIsNullGetDB(tx *gorm.DB, ado *gorm.DB) *gorm.DB {
	if tx == nil {
		return ado
	}
	return tx
}

// WithContext 创建上下文
func WithContext(c context.Context) context.Context {
	if c == nil {
		return context.Background()
	}
	return c
}
